package com.xinjian.jianba.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.xinjian.jianba.config.RedissonManager;
import com.xinjian.jianba.dao.dwmid.ShopListDao;
import com.xinjian.jianba.dto.IndexDto;
import com.xinjian.jianba.dto.MeetAddressDto;
import com.xinjian.jianba.dto.MeetAddressVo;
import com.xinjian.jianba.dto.ShopDetailVo;
import com.xinjian.jianba.dto.ShopListDto;
import com.xinjian.jianba.dto.geo.GeoResult;
import com.xinjian.jianba.dto.geo.Results;
import com.xinjian.jianba.enity.ShopListEntity;
import com.xinjian.jianba.exception.BusinessException;
import com.xinjian.jianba.exception.ResponseCode;
import com.xinjian.jianba.service.RedisService;
import com.xinjian.jianba.service.ShopListService;
import com.xinjian.jianba.utils.JsonUtil;
@Service
public class ShopListServiceImpl implements ShopListService {

	private static final Logger LOGGER = LoggerFactory.getLogger(ShopListServiceImpl.class);
	private static final String SHOP_REDIS_LOCK="SHOP_DATA_INIT";
	@Autowired
	private ShopListDao shopListDao;
	@Autowired
	private RedisService redisService;
	@Autowired
	private RedissonManager redissonManager;
	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	@Value("${jianba.shop.key}")
	private String shopkey;
	@Value("${jianba.shop.shopDistance}")
	private Double shopDistance;
	@Value("${jianba.shop.shopCount}")
	private Integer shopCount;
	
	@Override
	public List<ShopDetailVo> selectAll(ShopListDto shopListDto) {
		long count=redisService.count(shopkey);
		List<Results> resultList=new ArrayList<Results>();
		List<ShopDetailVo> resultListVo=new ArrayList<ShopDetailVo>();
		int num=0;
		if(count>0){
			lastVo(shopListDto,  resultList, resultListVo, num);
			
		}else{
			RLock lock = redissonManager.getRedisson().getLock(SHOP_REDIS_LOCK);
	        boolean getLock = false;
	        try {
	            if(getLock = lock.tryLock(0,50, TimeUnit.SECONDS)){
	            	LOGGER.info("Redisson获取到分布式锁:{},ThreadName:{}",SHOP_REDIS_LOCK,Thread.currentThread().getName());
	            	List<ShopListEntity> list=shopListDao.selectAll(new ShopListEntity());
	    			Map<String, String> map = new HashMap<String, String>();
	    			Map<String,Point> shopMap=new HashMap<String,Point>();
	    			list.stream().forEach(shopListEntity ->{
	    				map.put(shopkey+":"+shopListEntity.getShop_Id(), JsonUtil.getJsonString(shopListEntity));
	    				shopMap.put(shopListEntity.getShop_Id()+"", new Point(shopListEntity.getLngfloat(),shopListEntity.getLatfloat()));
	    			});
	    			redisTemplate.opsForValue().multiSet(map);
	    			redisTemplate.opsForGeo().geoAdd(shopkey, shopMap);
	            }else{
	            	LOGGER.info("Redisson没有获取到分布式锁:{},ThreadName:{}",SHOP_REDIS_LOCK,Thread.currentThread().getName());
	            }
	        } catch (InterruptedException e) {
	        	LOGGER.error("Redisson分布式锁获取异常",e);
	        } finally {
	            if(!getLock){
	                throw new BusinessException(ResponseCode.ERROR, "请稍后再试!");
	            }
	            lock.unlock();
	            LOGGER.info("Redisson分布式锁释放锁");
	            lastVo(shopListDto,resultList, resultListVo, num);
	        }
			
		}
		
		return resultListVo;
	}

	private void lastVo(ShopListDto shopListDto, List<Results> resultList,
			List<ShopDetailVo> resultListVo, int num) {
		GeoResults<GeoLocation<String>> geoResults=redisService.radiusGeo(shopkey, shopListDto.getLngfloat(), shopListDto.getLatfloat(), shopDistance, shopCount, DistanceUnit.METERS);
		GeoResult geoResult = JsonUtil.json2Obj(JsonUtil.getJsonString(geoResults), GeoResult.class);
		getPage(geoResult.getResults(), shopListDto, num, resultList);
		List<Long> shopidList = new ArrayList<Long>();
		resultList.stream().forEach(result -> {
			ShopDetailVo shopDetailVo=new ShopDetailVo();
			acquireResultsVo(shopDetailVo, resultListVo, result);
		});
	}

	private void acquireResultsVo(ShopDetailVo shopDetailVo, List<ShopDetailVo> resultListVo, Results result) {
		if (StringUtils.isNotBlank(result.getContent().getName())) {
			long shopid = Long.parseLong(result.getContent().getName());
			String json=null;
			ShopListEntity shopListEntity=null;
			try {
				json = redisService.get(shopkey+":"+shopid);
				if(json!=null){
					shopListEntity=JsonUtil.json2Obj(json, ShopListEntity.class);
				}else{
					shopListEntity=shopListDao.findByShopId(shopid);
					if(shopListEntity!=null){
					String jsonstr=JsonUtil.getJsonString(shopListEntity);
					redisService.set(shopkey+":"+shopid, jsonstr);
//					redisTemplate.opsForGeo().geoAdd(shopkey, new Point(shopListEntity.getLngfloat(),shopListEntity.getLatfloat()), shopListEntity.getShop_Id()+"");
					}else{
						redisTemplate.opsForGeo().geoRemove(shopkey, shopid+"");
						return;
					}
				}
			} catch (Exception e) {
				throw new BusinessException(ResponseCode.ERROR, e.getMessage());
			}
			shopDetailVo.setDistance(String.valueOf(result.getDistance().getValue()));
			setResultsVo(shopDetailVo, resultListVo, shopListEntity);
		}
	}

	private void setResultsVo(ShopDetailVo shopDetailVo, List<ShopDetailVo> resultListVo,
			ShopListEntity shopListEntity) {
		
		shopDetailVo.setLatfloat(new BigDecimal(shopListEntity.getLatfloat()));
		shopDetailVo.setLngfloat(new BigDecimal(shopListEntity.getLngfloat()));
		shopDetailVo.setSiteId(shopListEntity.getSite_id());
		shopDetailVo.setSiteName(shopListEntity.getSite_name());
		shopDetailVo.setShopId(String.valueOf(shopListEntity.getShop_Id()));
		shopDetailVo.setShopName(shopListEntity.getShop_name());
		shopDetailVo.setShopType(String.valueOf(shopListEntity.getShop_type()));
		resultListVo.add(shopDetailVo);
	}

	@Override
	public int addShop(ShopListEntity shopListEntity) {
		// TODO Auto-generated method stub
		return 0;
	}
	private void getPage(List<Results> results, ShopListDto shopListDto, Integer count, List<Results> resultList) {
		if (!CollectionUtils.isEmpty(results) && results.size() > 0) {
			int totalCount = results.size();
			int startIndex = (shopListDto.getPageNumber() - 1) * shopListDto.getPageSize() + 1;
			int endIndex = shopListDto.getPageNumber() * shopListDto.getPageSize();
			endIndex = endIndex > totalCount ? totalCount : endIndex;
			if (startIndex <= endIndex && startIndex != 0) {
				for (int i = startIndex; i <= endIndex; i++) {
					resultList.add(results.get(i - 1));
				}
			}
			count = totalCount;
		}

	}

}
